package com.gaokuo.es;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.gaokuo.es.property.FuncFieldNameUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.bucket.histogram.ParsedDateHistogram;
import org.elasticsearch.search.aggregations.bucket.range.RangeAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.*;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.util.List;

@Slf4j
public class CountTest {
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("10.10.20.113", 9200, "http"))
    );
    ObjectMapper mapper = new ObjectMapper();


    /**
     * 统计特殊值
     */
    @Test
    public void countSpecial() throws IOException {
        SearchRequest request = new SearchRequest();
        request.indices("person");
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //最大值
        MaxAggregationBuilder maxAgeBuilder = AggregationBuilders.max("maxAge").field(FuncFieldNameUtil.get(Person::getAge));
        builder.aggregation(maxAgeBuilder);

        //平均值
        AvgAggregationBuilder avgAgeBuilder = AggregationBuilders.avg("avgAge").field(FuncFieldNameUtil.get(Person::getAge));
        builder.aggregation(avgAgeBuilder);

        //去重计数 count(distinct ...)
        CardinalityAggregationBuilder ageCaBuilder = AggregationBuilders.cardinality("ageCa").field(FuncFieldNameUtil.get(Person::getAge));
        ageCaBuilder.precisionThreshold(Integer.MAX_VALUE);
        builder.aggregation(ageCaBuilder);

        //统计大全
        ExtendedStatsAggregationBuilder ageExtendedStatsBuilder = AggregationBuilders.extendedStats("ageExtendedStats").field(FuncFieldNameUtil.get(Person::getAge));
        builder.aggregation(ageExtendedStatsBuilder);

        //分组之后再进行统计
        TermsAggregationBuilder ageTermBuilder = AggregationBuilders.terms("ageTerms").field(FuncFieldNameUtil.get(Person::getAge));
        //对每个年龄的统计男女数量
        TermsAggregationBuilder sexTermBuilder = AggregationBuilders.terms("sexTerms").field(FuncFieldNameUtil.get(Person::getSex));
        ageTermBuilder.subAggregation(sexTermBuilder);
        builder.aggregation(ageTermBuilder);

        //根据出生日期分时间段统计
        //calendar_interval:根据指定单位统计
        //fixed_interval:根据执行时长分割统计
        //calendar_interval 支持 1 年、 1 季度、 1 月、 1 周、 1 天、 1 小时、 1 分钟，不支持时间为复数， fixed_interval 支持的时间单位为天、小时、分、秒、 毫秒，允许复数，例如"fixed_interval" : "30d" ，表示为 30 天。
        DateHistogramAggregationBuilder dateHisBirthdayBuilder = AggregationBuilders.dateHistogram("dateHisBirthday")
                .field(FuncFieldNameUtil.get(Person::getBirthday)).calendarInterval(DateHistogramInterval.YEAR);
        builder.aggregation(dateHisBirthdayBuilder);

        //范围 数字时间ip都可 IpRangeAggregationBuilder  DateRangeAggregationBuilder
        RangeAggregationBuilder ageRangeBuilder = AggregationBuilders.range("ageRange")
                .field(FuncFieldNameUtil.get(Person::getAge));
        ageRangeBuilder.addUnboundedFrom(21);
        ageRangeBuilder.addUnboundedTo(21);
        ageRangeBuilder.addRange(21,22);
        builder.aggregation(ageRangeBuilder);

        //先过滤再聚集
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.filter(QueryBuilders.termsQuery(FuncFieldNameUtil.get(Person::getSex),"女"));
        FilterAggregationBuilder sexFilterBuilder = AggregationBuilders.filter("sexFilter",boolQuery);
        sexFilterBuilder.subAggregation(avgAgeBuilder);
        builder.aggregation(sexFilterBuilder);

        request.source(builder);
        log.info("req:{}",request.source());
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        SearchHits hits = response.getHits();

        log.info("TotalHits===>{}",hits.getTotalHits());
        log.info("Took===>{}",response.getTook());

        ParsedMax maxAge = response.getAggregations().get("maxAge");
        log.info("maxAge===>"+maxAge.value());

        ParsedAvg avgAge = response.getAggregations().get("avgAge");
        log.info("avgAge===>"+avgAge.value());

        ParsedCardinality ageCa = response.getAggregations().get("ageCa");
        log.info("ageCa===>"+ageCa.value());

        log.info("日期统计===>");
        ParsedDateHistogram dateHisBirthday = response.getAggregations().get("dateHisBirthday");
        List<? extends Histogram.Bucket> birthdayBuckets = dateHisBirthday.getBuckets();
        for (Histogram.Bucket bucket : birthdayBuckets) {
            log.info("出生年：" + bucket.getKeyAsString().substring(0,4) + ":" + bucket.getDocCount());
        }
        log.info("年龄男女统计===>");
        ParsedTerms ageTerms = response.getAggregations().get("ageTerms");
        List<? extends Terms.Bucket> ageTermsBuckets = ageTerms.getBuckets();
        for (Terms.Bucket bucket : ageTermsBuckets) {
            ParsedTerms sexTerms = bucket.getAggregations().get("sexTerms");
            List<? extends Terms.Bucket> sexTermsBuckets = sexTerms.getBuckets();
            for (Terms.Bucket bucket1 : sexTermsBuckets) {
                log.info("年龄：{}，人数：{}，其中：{}：{}",bucket.getKey(),bucket.getDocCount(),bucket1.getKeyAsString(),bucket1.getDocCount());
            }
        }
    }
}
